const seedrandom = require('seedrandom');

/**
 * Math.random 的升级： seedRandom 函数
 * 以上几种方法因为策略简单，所以生成的随机数结果都不够完美，数据分布过于集中。
 * github 上找到了一个相关的包， seedrandom, 它利用更加复杂的算法，计算结果分散，并且支持中英文数字等多种格式
 *
 * https://juejin.cn/post/7241187132890923069
 * */

// 利用三角正弦函数，所以只支持数字
const seedRandom = seed => {
  return ('0.'+Math.sin(seed).toString().substr(6))
}


/**
 * seedrandom库使用一个称为"mulberry32"的 线性同余生成器。
 *
 * 我希望每天的抽奖奖品都可以从100个奖品库中随机选择 5 种，在当天内是不变的，怎么实现这个需求呢？
 * 对于这个需求，日期就是 seed 种子，日期不变情况下可重复计算出一个固定的随机数
 *
 * */


const rng = seedrandom( '2023-07-19' )
 // 生成 0 - 1之间的小数
console.log(rng());
console.log(rng());
console.log(rng());

/**
 * 洗牌算法
 * 原理就是遍历数组元素，将当前元素与随机抽取的一个剩余元素进行交换
 * 洗牌算法可以确保每个元素在洗牌后的序列中的概率均等
 * 在实际应用中应该选择合适的随机数生成器，以保证生成的随机数具有良好的随机性和均匀性。
 *
 * Fisher–Yates shuffle
 * https://juejin.cn/post/7037769373586554910
 * */

function shuffle(arr) {
  let length = arr.length;
  let random = 0
  while (0 !== length) {
    random = Math.floor(Math.random() * length)
    length--;
    [arr[length], arr[random]] = [arr[random], arr[length]]
  }
  return arr;
}

function shuffleSec(arr){
  let length = arr.length
  let random = 0;
  while(0 !== length){
    random =  (Math.random() * length--) >>> 0;  // 利用无符号右移位运算符向下取整方式
    [arr[length], arr[random]] = [arr[random], arr[length]]
  }
  return arr;
}



let arr = [1,2,3,4,5,6];
console.log(shuffle(arr))
console.log(shuffleSec(arr))

export {
  shuffle as shuffleSec
}
